

/*
 * Copyright (c) 2021. Dylan Cai
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//package com.dylanc.longan
package com.gitee.wsl.android.ext.device

import android.app.ActivityManager
import android.app.WallpaperManager
import android.content.ComponentName
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import android.text.format.Formatter.formatFileSize
import com.gitee.wsl.android.ext.ApplicationInit.application
import timber.log.Timber
import java.io.BufferedReader
import java.io.File
import java.io.FileFilter
import java.io.FileReader
import java.io.InputStream
import java.io.InputStreamReader
import java.io.LineNumberReader
import java.util.*
import java.util.regex.Pattern


object DeviceInfo {
    inline val sdkVersionName: String get() = Build.VERSION.RELEASE

    inline val sdkVersionCode: Int get() = Build.VERSION.SDK_INT

    inline val deviceManufacturer: String get() = Build.MANUFACTURER

    inline val deviceModel: String get() = Build.MODEL

    fun isComponentEnabled(pm: PackageManager, pkgName: String, clsName: String): Boolean {
        val componentName = ComponentName(pkgName, clsName)
        return when (pm.getComponentEnabledSetting(componentName)) {
            PackageManager.COMPONENT_ENABLED_STATE_DISABLED -> false
            PackageManager.COMPONENT_ENABLED_STATE_ENABLED -> true
            PackageManager.COMPONENT_ENABLED_STATE_DEFAULT ->                 // We need to get the application info to get the component's default state
                try {
                    val packageInfo = pm.getPackageInfo(
                        pkgName,
                        PackageManager.GET_PROVIDERS or PackageManager.GET_DISABLED_COMPONENTS
                    )
                    if (packageInfo.providers != null) {
                        Arrays.stream(packageInfo.providers)
                            .anyMatch { pi -> pi.name.equals(clsName) && pi.isEnabled }
                    } else false

                    // the component is not declared in the AndroidManifest
                } catch (e: PackageManager.NameNotFoundException) {
                    // the package isn't installed on the device
                    false
                }
            else -> try {
                val packageInfo = pm.getPackageInfo(
                    pkgName,
                    PackageManager.GET_PROVIDERS or PackageManager.GET_DISABLED_COMPONENTS
                )
                if (packageInfo.providers != null) {
                    Arrays.stream(packageInfo.providers)
                        .anyMatch { pi -> pi.name.equals(clsName) && pi.isEnabled }
                } else false
            } catch (e: PackageManager.NameNotFoundException) {
                false
            }
        }
    }

    object CPU{
        /**
         * 获取处理器的 Java 虚拟机的数量
         * @return 处理器的 Java 虚拟机的数量
         */
        fun getProcessorsCount(): Int {
            return Runtime.getRuntime().availableProcessors()
        }

        /**
         * 获取手机 CPU 序列号
         * @return CPU 序列号 (16 位 ) 读取失败为 "0000000000000000"
         */
        fun getSysCPUSerialNum(): String {
            var str: String
            var cpuSerialNum = "0000000000000000"
            try {
                // 读取 CPU 信息
                val pp = Runtime.getRuntime().exec("cat/proc/cpuinfo")
                val isr = InputStreamReader(pp.inputStream)
                val input = LineNumberReader(isr)
                // 查找 CPU 序列号
                for (i in 1..99) {
                    str = input.readLine()
                    if (str != null) {
                        // 查找到序列号所在行
                        if (str.contains("Serial")) {
                            // 提取序列号
                            cpuSerialNum = str.substring(str.indexOf(':') + 1).trim { it <= ' ' }
                            break
                        }
                    } else {
                        break
                    }
                }
            } catch (e: Exception) {
                Timber.d( e, "getSysCPUSerialNum")
            }
            return cpuSerialNum
        }

        /**
         * 获取 CPU 信息
         * @return CPU 信息
         */
        fun getCpuInfo(): String? {
            try {
                val fr = FileReader("/proc/cpuinfo")
                val br = BufferedReader(fr)
                return br.readLine()
            } catch (e: Exception) {
                Timber.d( e, "getCpuInfo")
            }
            return ""
        }

        /**
         * 获取 CPU 型号
         * @return CPU 型号
         */
        fun getCpuModel(): String {
            try {
                val fr = FileReader("/proc/cpuinfo")
                val br = BufferedReader(fr)
                val text = br.readLine()
                return text.split(":\\s+".toRegex(), limit = 2).toTypedArray()[1]
            } catch (e: Exception) {
                Timber.d( e, "getCpuModel")
            }
            return ""
        }

        /**
         * 获取 CPU 最大频率 ( 单位 KHZ )
         * @return CPU 最大频率 ( 单位 KHZ )
         */
        fun getMaxCpuFreq(): String {
            val cmd: ProcessBuilder
            var `is`: InputStream? = null
            try {
                val builder = StringBuilder()
                val args = arrayOf(
                    "/system/bin/cat",
                    "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq"
                )
                cmd = ProcessBuilder(*args)
                val process = cmd.start()
                `is` = process.inputStream
                val re = ByteArray(24)
                while (`is`.read(re) != -1) {
                    builder.append(String(re))
                }
                return formatFileSize(
                    application,
                    builder.toString().trim { it <= ' ' }.toLong() * 1024
                ) + " Hz"
            } catch (e: Exception) {
                Timber.d( e, "getMaxCpuFreq")
            } finally {
                `is`?.close()
            }
            return "unknown"
        }

        /**
         * 获取 CPU 最小频率 ( 单位 KHZ )
         * @return CPU 最小频率 ( 单位 KHZ )
         */
        fun getMinCpuFreq(): String {
            val cmd: ProcessBuilder
            var `is`: InputStream? = null
            try {
                val builder = StringBuilder()
                val args = arrayOf(
                    "/system/bin/cat",
                    "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq"
                )
                cmd = ProcessBuilder(*args)
                val process = cmd.start()
                `is` = process.inputStream
                val re = ByteArray(24)
                while (`is`.read(re) != -1) {
                    builder.append(String(re))
                }
                return formatFileSize(
                    application,
                    builder.toString().trim { it <= ' ' }.toLong() * 1024
                ) + " Hz"
            } catch (e: Exception) {
                Timber.d( e, "getMinCpuFreq")
            } finally {
                `is`?.close()
            }
            return "unknown"
        }

        /**
         * 获取 CPU 当前频率 ( 单位 KHZ )
         * @return CPU 当前频率 ( 单位 KHZ )
         */
        fun getCurCpuFreq(): String {
            try {
                val fr = FileReader(
                    "/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq"
                )
                val br = BufferedReader(fr)
                val text = br.readLine()
                return formatFileSize(
                    application,
                    text.trim { it <= ' ' }.toLong() * 1024
                ) + " Hz"
            } catch (e: Exception) {
                Timber.d( e, "getCurCpuFreq")
            }
            return "unknown"
        }

        /**
         * 获取 CPU 核心数
         * @return CPU 核心数
         */
        fun getCoresNumbers(): Int {
            // Private Class to display only CPU devices in the directory listing
            class CpuFilter : FileFilter {
                override fun accept(pathname: File): Boolean {
                    // Check if filename is "cpu", followed by a single digit number
                    return Pattern.matches("cpu[0-9]+", pathname.name)
                }
            }
            // CPU 核心数
            var CPU_CORES = 0
            try {
                // Get directory containing CPU info
                val dir = File("/sys/devices/system/cpu/")
                // Filter to only list the devices we care about
                val files = dir.listFiles(CpuFilter())
                // Return the number of cores ( virtual CPU devices )
                CPU_CORES = files.size
            } catch (e: Exception) {
                Timber.d( e, "getCoresNumbers")
            }
            if (CPU_CORES < 1) {
                CPU_CORES = Runtime.getRuntime().availableProcessors()
            }
            if (CPU_CORES < 1) {
                CPU_CORES = 1
            }
            return CPU_CORES
        }

        /**
         * 获取 CPU 名字
         * @return CPU 名字
         */
        fun getCpuName(): String? {
            var br: BufferedReader? = null
            try {
                br = BufferedReader(FileReader("/proc/cpuinfo"), 8192)
                val line = br.readLine()
                val array = line.split(":\\s+".toRegex(), limit = 2).toTypedArray()
                if (array.size > 1) {
                    return array[1]
                }
            } catch (e: Exception) {
                Timber.d( e, "getCpuName")
            } finally {
                br?.close()
            }
            return null
        }

        /**
         * 获取 CMD 指令回调数据
         * @param strings 指令集
         * @return 执行结果
         */
        fun getCMDOutputString(strings: Array<String?>): String? {
            var `is`: InputStream? = null
            try {
                val cmd = ProcessBuilder(*strings)
                val process = cmd.start()
                `is` = process.inputStream
                val builder = StringBuilder()
                val re = ByteArray(64)
                var len: Int
                while (`is`.read(re).also { len = it } != -1) {
                    builder.append(String(re, 0, len))
                }
                `is`.close()
                process.destroy()
                return builder.toString()
            } catch (e: Exception) {
                Timber.d( e, "getCMDOutputString")
            } finally {
                `is`?.close()
            }
            return null
        }
    }


    object Memory{

        // 内存信息文件地址
        private const val MEM_INFO_PATH = "/proc/meminfo"

        // 获取内存总大小
        private const val MEMTOTAL = "MemTotal"

        // 获取可用内存
        private const val MEMAVAILABLE = "MemAvailable"

        /**
         * 获取内存信息
         * @return 内存信息
         */
        fun printMemoryInfo(): String? {
            var br: BufferedReader? = null
            try {
                br = BufferedReader(FileReader(MEM_INFO_PATH), 4 * 1024)
                val builder = java.lang.StringBuilder()
                var str: String?
                while (br.readLine().also { str = it } != null) {
                    builder.append(str)
                }
                return builder.toString()
            } catch (e: java.lang.Exception) {
                Timber.d( e, "printMemoryInfo")
            } finally {
                br?.close()
            }
            return null
        }

        /**
         * 获取内存信息
         * @return 内存信息
         */
        fun printMemoryInfo2(): String? {
            try {
                val memoryInfo = getMemoryInfo() ?: return null
                val builder = java.lang.StringBuilder()
                builder.append("Memory: ")
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                    builder.append("\ntotalMem: ").append(memoryInfo.totalMem)
                }
                builder.append("\navailMem: ").append(memoryInfo.availMem)
                builder.append("\nlowMemory: ").append(memoryInfo.lowMemory)
                builder.append("\nthreshold: ").append(memoryInfo.threshold)
                return builder.toString()
            } catch (e: java.lang.Exception) {
                Timber.d( e, "printMemoryInfo2")
            }
            return null
        }

        /**
         * 获取内存信息
         * @return 内存信息
         */
        fun getMemoryInfo(): ActivityManager.MemoryInfo? {
            try {
                val activityManager: ActivityManager = application.activityManager
                val memoryInfo = ActivityManager.MemoryInfo()
                activityManager.getMemoryInfo(memoryInfo)
                return memoryInfo
            } catch (e: java.lang.Exception) {
                Timber.d( e, "getMemoryInfo")
            }
            return null
        }


        // =
        /**
         * 获取可用内存信息
         * @return 可用内存信息
         */
        fun getAvailMemory(): Long {
            try {
                // 获取 android 当前可用内存大小
                val activityManager: ActivityManager = application.activityManager
                val memoryInfo = ActivityManager.MemoryInfo()
                activityManager.getMemoryInfo(memoryInfo)
                // 当前系统的可用内存
                return memoryInfo.availMem
            } catch (e: java.lang.Exception) {
                Timber.d( e, "getAvailMemory")
            }
            return 0L
        }

        /**
         * 获取可用内存信息 ( 格式化 )
         * @return 可用内存信息
         */

        fun getAvailMemoryFormat(): String? {
            return formatFileSize(application, getAvailMemory())
        }

        // =
        /**
         * 获取总内存大小
         * @return 总内存大小
         */
        fun getTotalMemory(): Long {
            return getMemInfoType(MEMTOTAL)
        }

        /**
         * 获取总内存大小 ( 格式化 )
         * @return 总内存大小
         */
        fun getTotalMemoryFormat(): String? {
            return formatFileSize(application, getTotalMemory())
        }

        // =

        // =
        /**
         * 获取可用内存大小
         * @return 可用内存大小
         */
        fun getMemoryAvailable(): Long {
            return getMemInfoType(MEMAVAILABLE)
        }

        /**
         * 获取可用内存大小 ( 格式化 )
         * @return 可用内存大小
         */
        fun getMemoryAvailableFormat(): String? {
            return formatFileSize(application, getMemoryAvailable())
        }

        /**
         * 通过不同 type 获取对应的内存信息
         * @param type 内存类型
         * @return 对应 type 内存信息
         */
        fun getMemInfoType(type: String?): Long {
            var br: BufferedReader? = null
            try {
                br = BufferedReader(FileReader(MEM_INFO_PATH), 4 * 1024)
                var str: String
                while (br.readLine().also { str = it } != null) {
                    if (str.contains(type!!)) {
                        break
                    }
                }
                // 拆分空格、回车、换行等空白符
                val array = str.split("\\s+".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
                // 获取系统总内存, 单位是 KB, 乘以 1024 转换为 Byte
                return array[1].toLong() * 1024
            } catch (e: java.lang.Exception) {
                Timber.d( e, "getMemInfoType %s", type)
            } finally {
                br?.close()
            }
            return 0L
        }
    }

    object Rom{
        inline val isXiaomiRom: Boolean get() = isRomOf("xiaomi")

        inline val isHuaweiRom: Boolean get() = isRomOf("huawei")

        inline val isOppoRom: Boolean get() = isRomOf("oppo")

        inline val isVivoRom: Boolean get() = isRomOf("vivo")

        inline val isOnePlusRom: Boolean get() = isRomOf("oneplus")

        inline val isSmartisanRom: Boolean get() = isRomOf("smartisan", "deltainno")

        inline val isMeiZuRom: Boolean get() = isRomOf("meizu")

        inline val isSamsungRom: Boolean get() = isRomOf("samsung")

        inline val isGoogleRom: Boolean get() = isRomOf("google")

        inline val isSonyRom: Boolean get() = isRomOf("sony")

        fun isRomOf(vararg names: String): Boolean =
            names.any { it.contains(Build.BRAND, true) || it.contains(Build.MANUFACTURER, true) }

        val isHarmonyOS: Boolean
            get() {
                try {
                    val clazz = Class.forName("com.huawei.system.BuildEx")
                    val classLoader = clazz.classLoader
                    if (classLoader != null && classLoader.parent == null) {
                        return clazz.getMethod("getOsBrand").invoke(clazz) == "harmony"
                    }
                } catch (e: ClassNotFoundException) {
                } catch (e: NoSuchMethodException) {
                } catch (e: Exception) {
                }
                return false
            }
    }

}

inline val Context.isWallpaperAllowed:Boolean get() = this.getSystemService(WallpaperManager::class.java).isSetWallpaperAllowed

val globalActivityManager:ActivityManager by lazy { application.activityManager }

val Context.activityManager:ActivityManager
    get() = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager